﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.ComponentModel;
using System.Text;
using System.Xml.Serialization;
using System.Security.Permissions;

namespace Dazzle {
    [Serializable]
    [TypeConverter(typeof(ParameterConverter))]
    public class Parameter : ICloneable, ISerializable {
        #region constructors

        public Parameter() { }

        public Parameter(Parameter copyParameter) {
            this.ParameterName = copyParameter.ParameterName;
            this.Type = copyParameter.Type;
            this.DefaultValue = copyParameter.DefaultValue;
            this.Value = copyParameter.Value;
        }

        public Parameter(SerializationInfo info, StreamingContext context) {
            this.ParameterName = info.GetString("ParameterName");
            this.Type = (ParameterType)info.GetValue("Type", typeof(ParameterType));
            this.DefaultValue = info.GetString("DefaultValue");
            this.Value = info.GetString("Value");
        }

        #endregion

        #region ParameterName

        private string _parameterName;

        /// <summary>
        /// Get or set parameter name.
        /// </summary>
        [Description("参数名称")]
        public string ParameterName {
            get { return _parameterName; }
            set {
                if (string.IsNullOrEmpty(value)) {
                    throw new ArgumentNullException("参数名称不能为空。");
                }

                _parameterName = value;
            }
        }

        #endregion

        #region Type

        private ParameterType _type = ParameterType.String;

        /// <summary>
        /// Get or set the parameter's type.
        /// </summary>
        [Description("参数类别")]
        public ParameterType Type {
            get { return _type; }
            set { _type = value; }
        }

        #endregion

        #region DefaultValue

        private string _defaultValue;

        /// <summary>
        /// Get or set the default value of parameter.
        /// </summary>
        [Description("参数默认值")]
        public string DefaultValue {
            get { return _defaultValue; }
            set {
                switch (Type) {
                    case ParameterType.Date:
                        DateTime dt;
                        if (DateTime.TryParse(value, out dt)) {
                            _defaultValue = dt.ToString("yyyy-MM-dd");
                        } else {
                            throw new ArgumentException(string.Format("参数{0}不是Date类型。", value));
                        }
                        break;
                    case ParameterType.Number:
                        int iv;
                        float fv;
                        if (int.TryParse(value, out iv)) {
                            _defaultValue = iv.ToString();
                        } else if (float.TryParse(value, out fv)) {
                            _defaultValue = iv.ToString();
                        } else {
                            throw new ArgumentException(string.Format("参数{0}不是Number类型。", value));
                        }
                        break;
                    case ParameterType.StockCode:
                    case ParameterType.IndustryCode:
                    case ParameterType.String:
                        _defaultValue = value;
                        break;
                    default:
                        _defaultValue = value;
                        break;
                }
            }
        }

        #endregion

        #region Value

        private string _value;

        /// <summary>
        /// Get or set the value of paramter.
        /// </summary>
        [ReadOnly(true)]
        [Description("参数值")]
        public string Value {
            get { return _value; }
            set {
                switch (Type) {
                    case ParameterType.Date:
                        DateTime dt;
                        if (DateTime.TryParse(value, out dt)) {
                            _value = dt.ToString("yyyy-MM-dd");
                        } else {
                            throw new ArgumentException(string.Format("参数{0}不是Date类型。", value));
                        }
                        break;
                    case ParameterType.Number:
                        int iv;
                        float fv;
                        if (int.TryParse(value, out iv)) {
                            _value = iv.ToString();
                        } else if (float.TryParse(value, out fv)) {
                            _value = iv.ToString();
                        } else {
                            throw new ArgumentException(string.Format("参数{0}不是Number类型。", value));
                        }
                        break;
                    case ParameterType.StockCode:
                    case ParameterType.IndustryCode:
                    case ParameterType.String:
                        _value = value;
                        break;
                    default:
                        _value = value;
                        break;
                }
            }
        }

        #endregion

        #region ICloneable

        public object Clone() {
            return new Parameter(this);
        }

        #endregion

        #region ISerializable

        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.AddValue("ParameterName", this.ParameterName);
            info.AddValue("Type", this.Type);
            info.AddValue("DefaultValue", this.DefaultValue);
            info.AddValue("Value", this.Value);
        }

        #endregion

        #region ParameterConverter class

        internal class ParameterConverter : ExpandableObjectConverter {
            public override object ConvertTo(ITypeDescriptorContext context,
                System.Globalization.CultureInfo culture,
                object value, Type destinationType) {
                if (destinationType == typeof(string) && value is Parameter) {
                    Parameter p = (Parameter)value;

                    return string.Format("{0}({1})", p.ParameterName, p.Type);
                }
                return base.ConvertTo(context, culture, value, destinationType);
            }
        }

        #endregion
    }

    public enum ParameterType {
        Number,
        String,
        Date,
        StockCode,
        IndustryCode
    }
}
